import Vue from 'vue';

const isServer = Vue.prototype.$isServer;

// 判断参数是否是其中之一
export function oneOf( value, validList ) {
	for ( let i = 0; i < validList.length; i++ ) {
		if ( value === validList[ i ] ) {
			return true;
		}
	}
	return false;
}

export function camelcaseToHyphen( str ) {
	return str.replace( /([a-z])([A-Z])/g, '$1-$2' ).toLowerCase();
}

// For Modal scrollBar hidden
let cached;

export function getScrollBarSize( fresh ) {
	if ( isServer ) return 0;
	if ( fresh || cached === undefined ) {
		const inner = document.createElement( 'div' );
		inner.style.width = '100%';
		inner.style.height = '200px';
		
		const outer = document.createElement( 'div' );
		const outerStyle = outer.style;
		
		outerStyle.position = 'absolute';
		outerStyle.top = 0;
		outerStyle.left = 0;
		outerStyle.pointerEvents = 'none';
		outerStyle.visibility = 'hidden';
		outerStyle.width = '200px';
		outerStyle.height = '150px';
		outerStyle.overflow = 'hidden';
		
		outer.appendChild( inner );
		
		document.body.appendChild( outer );
		
		const widthContained = inner.offsetWidth;
		outer.style.overflow = 'scroll';
		let widthScroll = inner.offsetWidth;
		
		if ( widthContained === widthScroll ) {
			widthScroll = outer.clientWidth;
		}
		
		document.body.removeChild( outer );
		
		cached = widthContained - widthScroll;
	}
	return cached;
}

// watch DOM change
export const MutationObserver = isServer ? false : window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver || false;

const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
const MOZ_HACK_REGEXP = /^moz([A-Z])/;

function camelCase( name ) {
	return name.replace( SPECIAL_CHARS_REGEXP, function ( _, separator, letter, offset ) {
		return offset ? letter.toUpperCase() : letter;
	} ).replace( MOZ_HACK_REGEXP, 'Moz$1' );
}

// getStyle
export function getStyle( element, styleName ) {
	if ( !element || !styleName ) return null;
	styleName = camelCase( styleName );
	if ( styleName === 'float' ) {
		styleName = 'cssFloat';
	}
	try {
		const computed = document.defaultView.getComputedStyle( element, '' );
		return element.style[ styleName ] || computed ? computed[ styleName ] : null;
	} catch ( e ) {
		return element.style[ styleName ];
	}
}

// firstUpperCase
function firstUpperCase( str ) {
	return str.toString()[ 0 ].toUpperCase() + str.toString().slice( 1 );
}

export { firstUpperCase };

// Warn
export function warnProp( component, prop, correctType, wrongType ) {
	correctType = firstUpperCase( correctType );
	wrongType = firstUpperCase( wrongType );
	console.error( `[iView warn]: Invalid prop: type check failed for prop ${ prop }. Expected ${ correctType }, got ${ wrongType }. (found in component: ${ component })` );    // eslint-disable-line
}

var Type = ( function () {
	var type = {};
	const toStr = Object.prototype.toString;
	var typeArr = [ 'String', 'Object', 'Number', 'Array', 'Undefined', 'Function', 'Null', 'Symbol' ];
	for ( var i = 0; i < typeArr.length; i++ ) {
		( function ( name ) {
			type[ 'is' + name ] = function ( obj ) {
				return toStr.call( obj ) === '[object ' + name + ']';
			}
		} )( typeArr[ i ] );
	}
	
	return type;
} )();
export { Type };

function typeOf( obj ) {
	const toString = Object.prototype.toString;
	const map = {
		'[object Boolean]': 'boolean',
		'[object Number]': 'number',
		'[object String]': 'string',
		'[object Function]': 'function',
		'[object Array]': 'array',
		'[object Date]': 'date',
		'[object RegExp]': 'regExp',
		'[object Undefined]': 'undefined',
		'[object Null]': 'null',
		'[object Object]': 'object'
	};
	return map[ toString.call( obj ) ];
}

// deepCopy
function deepCopy( data ) {
	const t = typeOf( data );
	let o;
	
	if ( t === 'array' ) {
		o = [];
	} else if ( t === 'object' ) {
		o = {};
	} else {
		return data;
	}
	
	if ( t === 'array' ) {
		for ( let i = 0; i < data.length; i++ ) {
			o.push( deepCopy( data[ i ] ) );
		}
	} else if ( t === 'object' ) {
		for ( let i in data ) {
			o[ i ] = deepCopy( data[ i ] );
		}
	}
	return o;
}

export { deepCopy };

// scrollTop animation
export function scrollTop( el, from = 0, to, duration = 500, endCallback ) {
	if ( !window.requestAnimationFrame ) {
		window.requestAnimationFrame = (
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame ||
			window.msRequestAnimationFrame ||
			function ( callback ) {
				return window.setTimeout( callback, 1000 / 60 );
			}
		);
	}
	const difference = Math.abs( from - to );
	const step = Math.ceil( difference / duration * 50 );
	
	function scroll( start, end, step ) {
		if ( start === end ) {
			endCallback && endCallback();
			return;
		}
		
		let d = ( start + step > end ) ? end : start + step;
		if ( start > end ) {
			d = ( start - step < end ) ? end : start - step;
		}
		
		if ( el === window ) {
			window.scrollTo( d, d );
		} else {
			el.scrollTop = d;
		}
		window.requestAnimationFrame( () => scroll( d, end, step ) );
	}
	
	scroll( from, to, step );
}

// Find components upward
function findComponentUpward( context, componentName, componentNames ) {
	if ( typeof componentName === 'string' ) {
		componentNames = [ componentName ];
	} else {
		componentNames = componentName;
	}
	
	let parent = context.$parent;
	let name = parent.$options.name;
	while ( parent && ( !name || componentNames.indexOf( name ) < 0 ) ) {
		parent = parent.$parent;
		if ( parent ) name = parent.$options.name;
	}
	return parent;
}

export { findComponentUpward };

// Find component downward
export function findComponentDownward( context, componentName ) {
	const childrens = context.$children;
	let children = null;
	
	if ( childrens.length ) {
		for ( const child of childrens ) {
			const name = child.$options.name;
			if ( name === componentName ) {
				children = child;
				break;
			} else {
				children = findComponentDownward( child, componentName );
				if ( children ) break;
			}
		}
	}
	return children;
}

// Find components downward
export function findComponentsDownward( context, componentName ) {
	return context.$children.reduce( ( components, child ) => {
		if ( child.$options.name === componentName ) components.push( child );
		const foundChilds = findComponentsDownward( child, componentName );
		return components.concat( foundChilds );
	}, [] );
}

// Find components upward
export function findComponentsUpward( context, componentName ) {
	let parents = [];
	const parent = context.$parent;
	if ( parent ) {
		if ( parent.$options.name === componentName ) parents.push( parent );
		return parents.concat( findComponentsUpward( parent, componentName ) );
	} else {
		return [];
	}
}

// Find brothers components
export function findBrothersComponents( context, componentName, exceptMe = true ) {
	let res = context.$parent.$children.filter( item => {
		return item.$options.name === componentName;
	} );
	let index = res.findIndex( item => item._uid === context._uid );
	if ( exceptMe ) res.splice( index, 1 );
	return res;
}

/* istanbul ignore next */
const trim = function ( string ) {
	return ( string || '' ).replace( /^[\s\uFEFF]+|[\s\uFEFF]+$/g, '' );
};

/* istanbul ignore next */
export function hasClass( el, cls ) {
	if ( !el || !cls ) return false;
	if ( cls.indexOf( ' ' ) !== -1 ) throw new Error( 'className should not contain space.' );
	if ( el.classList ) {
		return el.classList.contains( cls );
	} else {
		return ( ' ' + el.className + ' ' ).indexOf( ' ' + cls + ' ' ) > -1;
	}
}

/* istanbul ignore next */
export function addClass( el, cls ) {
	if ( !el ) return;
	let curClass = el.className;
	const classes = ( cls || '' ).split( ' ' );
	
	for ( let i = 0, j = classes.length; i < j; i++ ) {
		const clsName = classes[ i ];
		if ( !clsName ) continue;
		
		if ( el.classList ) {
			el.classList.add( clsName );
		} else {
			if ( !hasClass( el, clsName ) ) {
				curClass += ' ' + clsName;
			}
		}
	}
	if ( !el.classList ) {
		el.className = curClass;
	}
}

/* istanbul ignore next */
export function removeClass( el, cls ) {
	if ( !el || !cls ) return;
	const classes = cls.split( ' ' );
	let curClass = ' ' + el.className + ' ';
	
	for ( let i = 0, j = classes.length; i < j; i++ ) {
		const clsName = classes[ i ];
		if ( !clsName ) continue;
		
		if ( el.classList ) {
			el.classList.remove( clsName );
		} else {
			if ( hasClass( el, clsName ) ) {
				curClass = curClass.replace( ' ' + clsName + ' ', ' ' );
			}
		}
	}
	if ( !el.classList ) {
		el.className = trim( curClass );
	}
}

export const dimensionMap = {
	xs: '480px',
	sm: '768px',
	md: '992px',
	lg: '1200px',
	xl: '1600px',
};

export function setMatchMedia() {
	if ( typeof window !== 'undefined' ) {
		const matchMediaPolyfill = mediaQuery => {
			return {
				media: mediaQuery,
				matches: false,
				on() {
				},
				off() {
				},
			};
		};
		window.matchMedia = window.matchMedia || matchMediaPolyfill;
	}
}

export const sharpMatcherRegx = /#([^#]+)$/;


